
package stratego.java.ssm;

import java.awt.Point;
import java.util.HashMap;

import stratego.java.ssm.piece.Piece;

/**
 * <code>public class Player</code>
 * <p>
 * This class represents a player, who has a select group of pieces. This class serves as a way to
 * conglomerate all the pieces and locations belonging to a certain player into a class independent
 * of the game logic.
 * </p>
 * 
 * @author Mark Aligbe
 * 
 */
public class Player
{
	// A player should keep track of how many pieces it has
	private HashMap<Piece, Integer>	pieces;
	// A player should keep track of where its pieces are
	private HashMap<Point, Piece>	pieceLocation;
	// A player should know what number it is.
	private int	                    playerNum;
	
	/**
	 * <code>public Player(int num)</code>
	 * <p>
	 * Makes a new player with the selected player numbers. Is used to determine the gradient of the
	 * pieces.
	 * </p>
	 * 
	 * @param num
	 */
	public Player(int num)
	{
		// The initial capacity is the first prime number greater than 3*12 (12 is the number of
		// different pieces, and 3 is the multiplicand because that tends to give minimal collisions
		// with a good hashing function)
		pieces = new HashMap<Piece, Integer>(37, 0.9f);
		// Ditto, but the base is 40 this time
		pieceLocation = new HashMap<Point, Piece>(127, 0.9f);
		playerNum = num;
	}
	
	/**
	 * <code>public int getNum()</code>
	 * <p>
	 * Identifies the number of this player, which identifies its gradient and where it can place
	 * its pieces.
	 * </p>
	 * 
	 * @return 1 or 2 (red or blue, South or North).
	 */
	public int getNum()
	{
		return playerNum;
	}
	
	/**
	 * <code>public HashMap<Point, Piece> getPieceLocations()</code>
	 * <p>
	 * Returns the locations of this player's pieces.
	 * </p>
	 * 
	 * @return A HashMap&ltPoint, Piece&gt that maps a location to some piece.
	 */
	public HashMap<Point, Piece> getPieceLocations()
	{
		return pieceLocation;
	}
	
	/**
	 * <code>public void addPiece(Piece p, Point loc)</code>
	 * <p>
	 * Adds a piece at the specified location.
	 * </p>
	 * 
	 * @param p
	 *            - The Piece to add.
	 * @param loc
	 *            - The Point where the Piece is being placed.
	 */
	public void addPiece(Piece p, Point loc)
	{
		Integer count = pieces.get(p);
		if (count == null)
			pieces.put(p, 1);
		else
			pieces.put(p, count + 1);
		pieceLocation.put(loc, p);
	}
	
	/**
	 * <code>public boolean decrementPiece(Piece p)</code>
	 * <p>
	 * Decrements the amount of some piece that a player has and removes it from the current
	 * location in the Player's board.
	 * </p>
	 * 
	 * @param p
	 *            - The piece to decrement
	 * @return True if the count of this piece reached 0 as a result of the decrement (the piece was
	 *         removed from the mapping). False otherwise.
	 */
	public boolean decrementPiece(Piece p, Point loc)
	{
		Integer count = pieces.get(p);
		if (count == null)
			return false;
		else
		{
			count--;
			pieceLocation.remove(loc);
			if (count == 0)
			{
				pieces.remove(p);
				return true;
			}
			else
			{
				pieces.put(p, count);
				return false;
			}
		}
	}
	
	/**
	 * <code>public void updatePiece(Piece p, Point oldLoc, Point newLoc)</code>
	 * <p>
	 * "Moves" a piece from one location to another.
	 * </p>
	 * 
	 * @param p
	 *            - The piece to move.
	 * @param oldLoc
	 *            - The current location where this piece should reside.
	 * @param newLoc
	 *            - The new location to place this piece.
	 */
	public void updatePiece(Piece p, Point oldLoc, Point newLoc)
	{
		pieceLocation.remove(oldLoc);
		pieceLocation.put(newLoc, p);
	}
	
	/*
	 * (non-Javadoc)
	 * 
	 * @see java.lang.Object#hashCode()
	 */
	@Override
	public int hashCode()
	{
		final int prime = 31;
		int result = 1;
		result = prime * result + playerNum;
		return result;
	}
	
	/*
	 * (non-Javadoc)
	 * 
	 * @see java.lang.Object#equals(java.lang.Object)
	 */
	@Override
	public boolean equals(Object obj)
	{
		if (this == obj)
			return true;
		if (obj == null)
			return false;
		if (!(obj instanceof Player))
			return false;
		Player other = (Player) obj;
		if (playerNum != other.playerNum)
			return false;
		return true;
	}
}
